﻿using Hopeless.Metaphysical;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UCS.XNA.Utils;
using UCS.XNA.Utils.Animation;
using UCS.XNA.Utils.Math;

namespace Hopeless.Physical
{
    class Zombie : ITranslateAnimatable, IScalable
    {
        private const int BODY_WIDTH = 15;
        private const int BODY_HEIGHT = 5;
        private const int HEAD_DIAMETER = 5;

        private Rectangle _bodySpace;
        public Rectangle BodySpace
        {
            get { return _bodySpace; }
        }

        private Rectangle _headSpace;
        private Texture2D _bodyTexture;
        private Texture2D _headTexture;

        private Vector2 _position;
        public Vector2 Position
        {
            get { return _position; }
            set
            {
                _position = value;
                this.InitializeBodyHead();
            }
        }

        public Vector2 RelativeOrigin
        {
            get { return new Vector2(BODY_WIDTH / 2f, BODY_HEIGHT / 2f); }
        }

        private float _facingAngle = 0;
        public float FacingAngle
        {
            get { return _facingAngle; }
            set
            {
                _facingAngle = value;
                if (_facingAngle > Math.PI * 2)
                    _facingAngle = (float)(Math.PI * 2 - _facingAngle);
                else if (_facingAngle < 0)
                    _facingAngle = (float)(Math.PI * 2 + _facingAngle);
            }
        }

        private float _scale = 1f;
        public float Scale
        {
            get { return _scale; }
            set
            {
                _scale = value;
                this.InitializeBodyHead();
            }
        }

        private bool _falling = false;
        public bool Falling
        {
            get { return _falling; }
            set { _falling = value; }
        }

        public bool IsDead
        {
            get { return _life <= 0; }
        }

        private int _life = 30;
        private float _speed = 0.8f;
        private Random _random = new Random();

        public void Initialize()
        {
            _bodyTexture = GameResources.Content.Load<Texture2D>("Zombie_Body");
            _headTexture = GameResources.Content.Load<Texture2D>("Zombie_Head");
            this.InitializeBodyHead();
        }

        public void Update(GameTime gameTime)
        {
            var hero = HopelessGame.Universe.Hero;

            if (hero == null || _falling)
                return;

            var nextFacingAngle = (float)GeometricAlgebra.GetAngleBetweenVectors(_position, hero.Position);
            var cos = Math.Cos(_facingAngle + Math.PI / 2);
            var sin = Math.Sin(_facingAngle + Math.PI / 2);
            var dir = new Vector2((float)cos, (float)sin);
            dir.Normalize();
            var nextPosition = _position + dir * _speed;
            var nextSpace = new Rectangle((int)nextPosition.X, (int)nextPosition.Y, BODY_WIDTH, BODY_HEIGHT);

            var colliding = false;
            foreach (var zombie in HopelessGame.Universe.CurrentWave.SpawnedZombies.Where(z => z != this))
            {
                if (zombie == this)
                    continue;

                colliding = Physics.CheckRotatedRectanglesCollision(nextSpace, this.RelativeOrigin, nextFacingAngle, zombie.BodySpace, zombie.RelativeOrigin, zombie.FacingAngle);
                if (colliding)
                    break;
            }

            if (!colliding)
            {
                this.FacingAngle = nextFacingAngle;
                this.Position = nextPosition;
            }

            foreach (var zombie in HopelessGame.Universe.CurrentWave.SpawnedZombies.Where(z => z != this))
            {
                var diff = _position - zombie.Position;
                var dist = diff.Length();
                if (dist <= 30)
                {
                    diff.Normalize();
                    var offDist = (1f / dist) * 3;
                    var off = diff * offDist;
                    _position += off;
                }
            }

            this.ProcessHeroCollision();
        }

        private void ProcessHeroCollision()
        {
            var hero = HopelessGame.Universe.Hero;
            var colliding = Physics.CheckRotatedRectanglesCollision(_bodySpace, this.RelativeOrigin, _facingAngle, hero.BodySpace, hero.RelativeOrigin, hero.FacingAngle);
            if (colliding)
            {
                var direction = hero.Position - _position;
                direction.Normalize();
                Physics.ForceAnimations.Add(new ForceTranslateAnimation(hero, direction, 3f));
                hero.TakeDamage(10);
            }
        }

        public void Draw(GameTime gameTime)
        {
            GameResources.SpriteBatch.Begin();

            GameResources.SpriteBatch.Draw(_bodyTexture, _bodySpace, null, Color.White, _facingAngle, new Vector2(_bodyTexture.Width / 2, _bodyTexture.Height / 2), SpriteEffects.None, 0);
            GameResources.SpriteBatch.Draw(_headTexture, _headSpace, null, Color.White, 0, new Vector2(_headTexture.Width / 2, _headTexture.Height / 2), SpriteEffects.None, 0);

            GameResources.SpriteBatch.End();
        }

        public void TakeDamage(int damage)
        {
            _life -= damage;

            var count = _random.Next(1, 4);
            for (int i = 0; i < count; i++)
            {
                BloodSpill bloodSpill = new BloodSpill(_random.Next(2, 6));
                bloodSpill.Initialize();
                bloodSpill.Position = _position;
                bloodSpill.Scale = _scale;

                var ang = _facingAngle - Math.PI / 2f + _random.Next(-50, 51) / 100f;
                var cos = Math.Cos(ang);
                var sin = Math.Sin(ang);
                var dir = new Vector2((float)cos, (float)sin);

                Physics.Animations.Add(new OffsetTranslateAnimation(bloodSpill, dir, _random.Next(10, 16), 2));
                HopelessGame.Universe.BloodSpills.Add(bloodSpill);
            }

            if (damage >= 15)
            {
                var ang = _facingAngle - Math.PI / 2f + _random.Next(-50, 51) / 100f;
                var cos = Math.Cos(ang);
                var sin = Math.Sin(ang);
                var dir = new Vector2((float)cos, (float)sin);
                var bloodSpill = new BloodSpill(_random.Next(7, 11));
                bloodSpill.Initialize();
                bloodSpill.Position = _position;
                bloodSpill.Scale = _scale;

                Physics.Animations.Add(new OffsetTranslateAnimation(bloodSpill, dir, 7, 1));
                HopelessGame.Universe.BloodSpills.Add(bloodSpill);
            }
        }

        private void InitializeBodyHead()
        {
            _bodySpace = new Rectangle((int)_position.X, (int)_position.Y, (int)(BODY_WIDTH * _scale), (int)(BODY_HEIGHT * _scale));
            _headSpace = new Rectangle((int)_position.X, (int)_position.Y, (int)(HEAD_DIAMETER * _scale), (int)(HEAD_DIAMETER * _scale));
        }
    }
}
